<?php
/**
 * Fuyou.class.php 富友支付
 * ==============================================
 * Copy right
 * ----------------------------------------------
 * ==============================================
 * @author: 徐芳珍
 * @date: 2016年11月28日
 * @version: v1.0.0
 */
namespace Service\Pay\Fuyou;
defined('THINK_PATH') or exit();
use Service\Pay;
class Fuyou  extends Pay {
    protected $_errCode=array(
        '0' => '本次调用成功',
        '-100' => '环境变量"NPCDIR"未设置 需要在在Linux或Unix上设置环境变量NPCDIR',
        '-101' => '商户密钥文件不存在或无法打开 设置密钥文件为可写方式',
        '-102' => '密钥文件格式错误 可能商户的密钥文件在传输途中有误',
        '-103' => '参数错误 请检查参与签名的参数是否正确',
        '-112' => '公钥文件不存在或无法打开 设置密钥文件为可写方式',
        '-113' => '公钥文件格式错误 可能公钥文件在传输途中有误',
        '-301' => '验证签名出错 请检查参与签名的参数是否正确',
        '-401' => '参与签名的数据体超过规定长度',
        '1004' => '无签约信息，不能发起扣款',
        '1005' => '暂不支持的银行卡',
        '1008' => '短信发送过于频繁，请稍后再试',
        '1010' => '错误次数超限，请核对卡信息稍后再试',
        '1040' => '请求的功能尚不支持',
        '1096' => '系统异常、失效',
        '5185' => '订单已支付',
        '8110' => '验证码验证次数超限',
        '8143' => '验证码失效或错误',
        '9999' => '证件号必须为 15 或者 18 位',
        '0001' => '发送失败',
        '0020' => '手机号信息非法',
        '0021' => '订单号重复',
        '0030' => '报文内容信息非法',
        '10FC' => '借记卡单笔交易金额超限',
        '10FD' => '同卡金额超限',
        '10FE' => '贷记卡单笔交易金额超限',
        '10M1' => '超出借记卡同商户单日交易累计金额限额',
        '10M2' => '超出借记卡同商户当月累计金额限制',
        '10SM' => '超过金额限制',
        '51B3' => '订单支付中，请勿重复支付',
        '200012' => '报文格式错误',
        '200013' => '持卡人身份信息或手机号与银行预留不一致，或未开通银联在线功能',
        '200014' => '银行卡未开通银联在线功能或为不支持的卡',
        '200015' => '卡状态不正常',
        '200016' => '无效卡',
        '200017' => '银行卡账户余额不足',
        '200023' => '银联风险受限',
        '200029' => '交易金额超限',
        '200098' => '交易超时',
        '999998' => '交易失败，详情请咨询您的发卡行',
        '999999' => array(
            '0' => '系统异常',
            '1' => '交易通讯超时，请发起查询交易',
            '2' => '交易状态未明，请查询对账结果(04Z3003)',
            '3' => '请求的功能尚不支持',
            '4' => '正在日终处理'
        )
    );

    /**
     * @desc 构造函数
     * @author 徐芳珍
     */
    function __construct($options=array()) {
        if(empty($options)) {
            $pay_config = C('PAY_CONFIG');
            $options = isset($pay_config['Fuyou'])?$pay_config['Fuyou']:array();
        }
        $this->options = $options;
    }

    /**
     * @desc 获取错误描述
     * @author 徐芳珍
     */
    private function _getErrMsg($resp_code){
        if(isset($this->_errCode[$resp_code])){
            return $this->_errCode[$resp_code];
        }
        return $resp_code;
    }


    //XML编码
    private function _xml_encode($data, $root='think', $item='item', $attr='', $id='id', $encoding='utf-8') {
        if(is_array($attr)){
            $_attr = array();
            foreach ($attr as $key => $value) {
                $_attr[] = "{$key}=\"{$value}\"";
            }
            $attr = implode(' ', $_attr);
        }
        $attr   = trim($attr);
        $attr   = empty($attr) ? '' : " {$attr}";
        $xml    = "";
        $xml   .= "<{$root}{$attr}>";
        $xml   .= $this->_data_to_xml($data, $item, $id);
        $xml   .= "</{$root}>";
        return $xml;
    }

    //数据XML编码
    private function _data_to_xml($data, $item='item', $id='id') {
        $xml = $attr = '';
        foreach ($data as $key => $val) {
            if(is_numeric($key)){
                $id && $attr = " {$id}=\"{$key}\"";
                $key  = $item;
            }
            $xml    .=  "<{$key}{$attr}>";
            $xml    .=  (is_array($val) || is_object($val)) ? data_to_xml($val, $item, $id) : $val;
            $xml    .=  "</{$key}>";
        }
        return $xml;
    }

    //DES加密
    private function _encrypt($message_string) {
        $size = mcrypt_get_block_size('des', 'ecb');
        $message_string = $this->_pkcs5_pad($message_string, $size);
        $key = $this->options['key_password'];
        $td = mcrypt_module_open('des', '', 'ecb', '');
        $iv = @mcrypt_create_iv(mcrypt_enc_get_iv_size($td), MCRYPT_RAND);
        @mcrypt_generic_init($td, $key, $iv);
        $data = mcrypt_generic($td, $message_string);
        mcrypt_generic_deinit($td);
        mcrypt_module_close($td);
        $data = base64_encode($data);
        return $data;
    }

    private function _pkcs5_pad($text, $blocksize) {
        $pad = $blocksize - (strlen($text) % $blocksize);
        return $text . str_repeat(chr($pad), $pad);
    }

    //DES解密
    private function _decrypt($encrypted) {
        $encrypted = base64_decode($encrypted);
        $key = $this->options['key_password'];
        $td = mcrypt_module_open('des', '', 'ecb', '');
        //使用MCRYPT_DES算法,cbc模式
        $iv = @mcrypt_create_iv(mcrypt_enc_get_iv_size($td), MCRYPT_RAND);
        $ks = mcrypt_enc_get_key_size($td);
        @mcrypt_generic_init($td, $key, $iv);
        //初始处理
        $decrypted = mdecrypt_generic($td, $encrypted);
        //解密
        mcrypt_generic_deinit($td);
        //结束
        mcrypt_module_close($td);
        $y = $this->_pkcs5_unpad($decrypted);
        return $y;
    }

    private function _pkcs5_unpad($text) {
        $pad = ord($text{strlen($text) - 1});
        if ($pad > strlen($text))
            return false;
            if (strspn($text, chr($pad), strlen($text) - $pad) != $pad)
                return false;
                return substr($text, 0, -1 * $pad);
    }

    /**
     * @desc 发送相关短信
     * @author 徐芳珍
     * @param array $params
     *      userip:客户 IP
     *      mchntorderid:商户订单号
     *      userid:用户 ID
     *      amt:交易金额
     *      bankcard:银行卡号
     *      name:姓名
     *      idno:证件号
     *      mobile:银行预留手机号(接受短信)
     * @return array $rts
     *      rt:状态码
     *      msg:描述语
     */
    public function sendSms($params){
        $rts=array();
        if(!isset($params['userip']) || !$params['userip']){
            $rts['rt']=-1;
            $rts['msg']='客户 IP不能为空';
            return $rts;
        }
        if(!isset($params['mchntorderid']) || !$params['mchntorderid']){
            $rts['rt']=-2;
            $rts['msg']='商户订单号不能为空';
            return $rts;
        }
        if(!isset($params['userid']) || !$params['userid']){
            $rts['rt']=-3;
            $rts['msg']='用户 ID不能为空';
            return $rts;
        }
        if(!isset($params['amt']) || !$params['amt']){
            $rts['rt']=-4;
            $rts['msg']='交易金额不能为空';
            return $rts;
        }
        if(!isset($params['bankcard']) || !$params['bankcard']){
            $rts['rt']=-5;
            $rts['msg']='银行卡号不能为空';
            return $rts;
        }
        if(!isset($params['name']) || !$params['name']){
            $rts['rt']=-6;
            $rts['msg']='姓名不能为空';
            return $rts;
        }
        if(!isset($params['idno']) || !$params['idno']){
            $rts['rt']=-7;
            $rts['msg']='证件号不能为空';
            return $rts;
        }
        if(!isset($params['mobile']) || !$params['mobile']){
            $rts['rt']=-8;
            $rts['msg']='银行预留手机号不能为空';
            return $rts;
        }
        $url = $this->options['backurl'] . '?userid=' . $params['userid'];
        //拼接签名数据
        $sign = "";
        $sign .= $this->options['deal_type']."|";
        $sign .= $this->options['version']."|";
        $sign .= $this->options['mchntcd']."|";
        $sign .= $params['mchntorderid']."|";
        $sign .= $params['userid']."|";
        $sign .= $params['amt']."|";
        $sign .= $params['bankcard']."|";
        $sign .= $url."|";
        $sign .= $params['name']."|";
        $sign .= $params['idno']."|";
        $sign .= $this->options['idtype']."|";
        $sign .= $params['mobile']."|";
        $sign .= $params['userip']."|";
        $sign .= $this->options['key_password'];
        $sign = MD5($sign);

        $data = array(
            'VERSION'       => $this->options['version'],
            'MCHNTCD'       => $this->options['mchntcd'],
            'TYPE'          => $this->options['deal_type'],
            'MCHNTORDERID'  => $params['mchntorderid'],
            'USERID'        => $params['userid'],
            'AMT'           => $params['amt'],
            'BANKCARD'      => $params['bankcard'],
            'NAME'          => $params['name'],
            'IDTYPE'        => $this->options['idtype'],
            'IDNO'          => $params['idno'],
            'MOBILE'        => $params['mobile'],
            'CVN'           => (isset($params['cvn'])?$params['cvn']:''),
            'BACKURL'       => $url,
            'REM1'          => (isset($params['rem1'])?$params['rem1']:''),
            'REM2'          => (isset($params['rem2'])?$params['rem2']:''),
            'REM3'          => (isset($params['rem3'])?$params['rem3']:''),
            'SIGNTP'        => $this->options['signtp'],
            'USERIP'        => $params['userip'],
            'SIGN'          => $sign,
        );

        $message_string = $this->_xml_encode($data,'REQUEST'); //转XML
        $encrypted = $this->_encrypt($message_string);  //DES加密

        $send_data = array();
        $send_data['MCHNTCD'] = $this->options['mchntcd'];
        $send_data['APIFMS'] = $encrypted;

        //curl模拟请求
        $return_data = $this->curl_post($this->options['orderAction'], $send_data);

        //处理返回的数据
        $decrypted = $this->_decrypt($return_data);  //DES解密，变成XML格式
        $res = json_decode(json_encode((array)simplexml_load_string($decrypted)), true); //XML转数组
        if($res['RESPONSECODE'] == '0000'){
            $rts['rt']=1;
            $rts['msg']=$res['RESPONSEMSG'];
            $rts['data']=$res;
        }else{
            $rts['rt']=$res['RESPONSECODE'];
            if(isset($this->_errCode[$res['RESPONSECODE']])){
                $rts['msg']=$this->_getErrMsg($res['RESPONSECODE']);
            }else{
                $msg=explode("|",$res['RESPONSEMSG']);
                $rts['msg']=trim($msg[0]);
            }
            $rts['data']=$res;
        }

        //记录日志
        third_party_api_log($this->options['orderAction'],$send_data,$res,$this->options['type']);
        return $rts;
    }

    /**
     * @desc 预绑定
     * @author 陈聪
     */
    public function preBind($params){

    }

    /**
     * @desc 绑定
     * @author 陈聪
     * @param array $params
     */
    public function bind($params){

    }

    /**
     * @desc 预解绑
     * @author 陈聪
     */
    public function preUnBind($params){
    }

    /**
     * @desc 解绑
     * @author 陈聪
     * @param array $params
     */
    public function unBind($params){
         return array('rt'=>1,'data'=>array());
    }

    /**
     * @desc 预支付-此处为发送短信
     * @author 陈聪
     * @param array $params
     */
    public function prePay($params){
        $data = array();
        $data['userip'] = $params['ip'];
        $data['mchntorderid'] = $params['order_sn'];
        $data['userid'] = $params['user_id'];
        $data['amt'] = floatval($params['amount'])*100;
        $data['bankcard'] = $params['bank_card_number'];
        $data['name'] = $params['card_name'];
        $data['idno'] = $params['id_card'];
        $data['mobile'] = $params['mobile'];
        $rts= $this->sendSms($data); //预支付接口
        if($rts['rt']==1){
            $params['fyorderid']=$rts['data']['ORDERID'];
            $params['signpay']=$rts['data']['SIGNPAY'];
            $rts['return_data']=$params;
        }
        return $rts;
    }

    /**
     * @desc 支付
     * @author 徐芳珍
     * @param array $params
     *      userip:客户 IP
     *      mchntorderid:商户订单号
     *      userid:用户 ID
     *      orderid:富友订单号
     *      bankcard:银行卡号
     *      mobile:银行预留手机号
     *      vercd:短信验证码
     *      signpay:下单验证码
     *
     * @return array $rts
     *      rt:状态码
     *      msg:描述语
     */
    public function pay($params){
        $rts=array();
        if(!isset($params['ip']) || !$params['ip']){
            $rts['rt']=-1;
            $rts['msg']='客户 IP不能为空';
            return $rts;
        }
        if(!isset($params['order_sn']) || !$params['order_sn']){
            $rts['rt']=-2;
            $rts['msg']='商户订单号不能为空';
            return $rts;
        }
        if(!isset($params['user_id']) || !$params['user_id']){
            $rts['rt']=-3;
            $rts['msg']='用户 ID不能为空';
            return $rts;
        }
        if(!isset($params['fyorderid']) || !$params['fyorderid']){
            $rts['rt']=-4;
            $rts['msg']='富友订单号不能为空';
            return $rts;
        }
        if(!isset($params['bank_card_number']) || !$params['bank_card_number']){
            $rts['rt']=-5;
            $rts['msg']='银行卡号不能为空';
            return $rts;
        }
        if(!isset($params['mobile']) || !$params['mobile']){
            $rts['rt']=-6;
            $rts['msg']='银行预留手机号不能为空';
            return $rts;
        }
        if(!isset($params['sms_code']) || !$params['sms_code']){
            $rts['rt']=-7;
            $rts['msg']='短信验证码不能为空';
            return $rts;
        }
        if(!isset($params['signpay']) || !$params['signpay']){
            $rts['rt']=-8;
            $rts['msg']='下单验证码不能为空';
            return $rts;
        }
        //拼接签名数据
        $sign = "";
        $sign .= $this->options['deal_type']."|";
        $sign .= $this->options['version']."|";
        $sign .= $this->options['mchntcd']."|";
        $sign .= $params['fyorderid']."|";
        $sign .= $params['order_sn']."|";
        $sign .= $params['user_id']."|";
        $sign .= $params['bank_card_number']."|";
        $sign .= $params['sms_code']."|";
        $sign .= $params['mobile']."|";
        $sign .= $params['ip']."|";
        $sign .= $this->options['key_password'];
        $sign = MD5($sign);

        $data = array(
            'TYPE'          => $this->options['deal_type'],
            'VERSION'       => $this->options['version'],
            'MCHNTCD'       => $this->options['mchntcd'],
            'ORDERID'       => $params['fyorderid'],
            'MCHNTORDERID'  => $params['order_sn'],
            'USERID'        => $params['user_id'],
            'BANKCARD'      => $params['bank_card_number'],
            'VERCD'          => $params['sms_code'],
            'MOBILE'        => $params['mobile'],
            'REM1'          => (isset($params['rem1'])?$params['rem1']:''),
            'REM2'          => (isset($params['rem2'])?$params['rem2']:''),
            'REM3'          => (isset($params['rem3'])?$params['rem3']:''),
            'SIGNTP'        => $this->options['signtp'],
            'USERIP'        => $params['ip'],
            'SIGN'          => $sign,
            'SIGNPAY'        => $params['signpay'],
        );

        $message_string = $this->_xml_encode($data,'REQUEST'); //转XML
        $encrypted = $this->_encrypt($message_string);  //DES加密

        $send_data = array();
        $send_data['MCHNTCD'] = $this->options['mchntcd'];
        $send_data['APIFMS'] = $encrypted;

        //curl模拟请求
        $return_data = $this->curl_post($this->options['payAction'], $send_data);

        //处理返回的数据
        $decrypted = $this->_decrypt($return_data);  //DES解密，变成XML格式
        $res = json_decode(json_encode((array)simplexml_load_string($decrypted)), true); //XML转数组
        if($res['RESPONSECODE'] == '0000'){
            $rts['rt']=1;
            $rts['msg']=$res['RESPONSEMSG'];
            $rts['data']=$res;
        }else{
            $rts['rt']=$res['RESPONSECODE'];
            if(isset($this->_errCode[$res['RESPONSECODE']])){
                $rts['msg']=$this->_getErrMsg($res['RESPONSECODE']);
            }else{
                $msg=explode("|",$res['RESPONSEMSG']);
                $rts['msg']=trim($msg[0]);
            }
            $rts['data']=$res;
        }

        //记录日志
        third_party_api_log($this->options['payAction'],$send_data,$res,$this->options['type']);
        return $rts;
    }

    /**
     * @desc 订单查询
     * @author 徐芳珍
     * @param string $mchntorderid 商户订单号
     * @return array $rts
     *      rt:状态码
     *      msg:描述语
     */
    public function queryPayStatus($params){
        $rts=array();
        if(!$params['order_sn']){
            $rts['rt']=-1;
            $rts['msg']='商户订单号不能为空';
            return $rts;
        }
        //拼接签名数据
        $sign = "";
        $sign .= $this->options['s_version']."|";
        $sign .= $this->options['mchntcd']."|";
        $sign .= $params['order_sn']."|";
        $sign .= $this->options['key_password'];
        $sign = MD5($sign);

        $data = array(
            'VERSION'       => $this->options['s_version'],
            'MCHNTCD'       => $this->options['mchntcd'],
            'MCHNTORDERID'  => $params['order_sn'],
            'REM1'          => (isset($params['rem1'])?$params['rem1']:''),
            'REM2'          => (isset($params['rem2'])?$params['rem2']:''),
            'REM3'          => (isset($params['rem3'])?$params['rem3']:''),
            'SIGN'          => $sign,
        );

        $message_string = $this->_xml_encode($data,'ORDER'); //转XML

        $send_data = array();
        $send_data['FM'] = $message_string;

        //curl模拟请求
        $return_data = $this->curl_post($this->options['checkResult'], $send_data);

        //处理返回的数据
        $return_json=json_encode((array)simplexml_load_string($return_data));
        $res = json_decode($return_json, true); //XML转数组
        $rts['return_data']=$res;
        if($res['RESPONSECODE']=='0000'){
            $rts['rt']=1;
            $rts['msg']='支付成功';
        }else{
            $rts['rt']=-1;
            if(isset($this->_errCode[$res['RESPONSECODE']])){
                $rts['msg']=$this->_getErrMsg($res['RESPONSECODE']);
            }else{
                $msg=explode("|",$res['RESPONSEMSG']);
                $rts['msg']=trim($msg[0]);
            }
        }
        return $rts;
    }
}